{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d808e8cb-c602-444c-a0a1-125306eb2746",
   "metadata": {},
   "source": [
    "# python-pptx 库快速入门\n",
    "\n",
    "`python-pptx` 是一个用于创建和修改 PowerPoint (.pptx) 文件的 Python 库。它允许用户通过代码动态生成演示文稿，适合自动化报告、演示和其他需要生成 PPT 的场景。\n",
    "\n",
    "以下是对 `python-pptx` 库的介绍以及如何将其抽象与 PowerPoint 母版中的内容、布局等概念对应起来的说明。\n",
    "\n",
    "###  `python-pptx` 库简介\n",
    "\n",
    "- **安装**：\n",
    "\n",
    "```bash\n",
    "  pip install python-pptx\n",
    "```\n",
    "\n",
    "- **功能**：\n",
    "  - 创建新的 PowerPoint 文件。\n",
    "  - 修改现有的 PPTX 文件。\n",
    "  - 添加文本框、图片、图表、表格等各种元素。\n",
    "  - 自定义幻灯片的布局和格式。\n",
    "\n",
    "### `python-pptx` 库抽象与母版中的概念对应\n",
    "\n",
    "在 `python-pptx` 中，可以将一些抽象概念与 PowerPoint 母版中的内容和布局对应起来：\n",
    "\n",
    "- **母版（Master Slide）**：\n",
    "  - 在 `python-pptx` 中，可以通过 `presentation.slide_master` 来访问母版。母版包含了幻灯片的基本格式和样式，可以定义统一的外观。\n",
    "\n",
    "- **布局（Layouts）**：\n",
    "  - 使用 `presentation.slide_layouts` 可以访问不同的幻灯片布局，例如标题幻灯片、内容幻灯片等。每种布局都有预定义的占位符，可以用于快速插入内容。\n",
    "\n",
    "- **内容类型（Content Types）**：\n",
    "  - 对应于文本框、图片、图表等内容类型，可以使用 `add_textbox()`、`add_picture()`、`add_table()`、`add_chart()` 等方法来添加这些元素。\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a5b8b4b6-8934-4603-88e0-7fe39211df3f",
   "metadata": {},
   "source": [
    "## `python-pptx` 库核心 数据结构与方法\n",
    "\n",
    "在 `python-pptx` 库中，主要的数据结构和方法帮助用户创建和修改 PowerPoint 演示文稿。以下是对上述代码中使用的数据结构和方法的详细介绍，包括 `Presentation`、`SlideLayout`、`Slide`、`Shape`、`Placeholder` 和 `TextFrame` 等。\n",
    "\n",
    "### 1. `Presentation` 类\n",
    "\n",
    "- **概述**：\n",
    "\n",
    "`Presentation` 是 `python-pptx` 中的核心类，用于表示一个 PowerPoint 演示文稿。\n",
    "\n",
    "- **构造方法**：\n",
    "\n",
    "创建一个新的空演示文稿。\n",
    "\n",
    "```python\n",
    "presentation = Presentation()\n",
    "```\n",
    "\n",
    "如果要打开现有的 PPTX 文件，可以传递文件路径：\n",
    "\n",
    "```python\n",
    "presentation = Presentation(\"existing_file.pptx\")\n",
    "```\n",
    "\n",
    "保存 PPTX 文件：\n",
    "\n",
    "```python\n",
    "presentation.save(\"example_presentation.pptx\")\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "006df3d4-36e7-455d-aa16-da5ef8da00e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pptx import Presentation\n",
    "from pptx.util import Inches"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "eb9e4ec4-f584-45b4-a60a-c366b78b3b67",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建一个新的 PowerPoint 文件\n",
    "presentation = Presentation()\n",
    "\n",
    "# 保存 PPTX 文件\n",
    "presentation.save(\"empty_presentation.pptx\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7b1e2e67-f6ae-4898-9d63-13386940b592",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 打开现有的 PPTX 文件，可以传递文件路径\n",
    "presentation = Presentation(\"../outputs/ChatPPT_Demo.pptx\")\n",
    "\n",
    "# 保存刚打开的 PPTX 文件\n",
    "presentation.save(\"ChatPPT_Demo.pptx\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4a352b5-6eb9-4477-8cc6-b627b51e70c0",
   "metadata": {},
   "source": [
    "### 2. `SlideLayout` 布局\n",
    "\n",
    "`SlideLayout` 表示一个幻灯片的布局，包含一组预定义的占位符和格式设置，定义了幻灯片的基本结构。\n",
    "\n",
    "**获取布局**：\n",
    "\n",
    "`presentation.slide_layouts`：这是一个布局列表，包含了所有可用的幻灯片布局。\n",
    "\n",
    "\n",
    "**单个布局**:\n",
    "\n",
    "```python\n",
    "slide_layout = presentation.slide_layouts[0]  # 标题幻灯片布局\n",
    "slide_layout = presentation.slide_layouts[1]  # 内容幻灯片\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "3ff7f338-cf69-4e45-b276-60b9ad405960",
   "metadata": {},
   "outputs": [],
   "source": [
    "template = Presentation(\"../templates/MasterTemplate.pptx\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "7cc18e3e-5244-44a0-8fa7-53c0ed0d68f3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<pptx.slide.SlideLayouts at 0x11365b130>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "template.slide_layouts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "473ff232-77e4-49d0-940c-98a2d53e2ab0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<pptx.slide.SlideLayout at 0x11365b940>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "slide_layout = template.slide_layouts[0]\n",
    "slide_layout"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "7d15b566-1c2c-45d1-8c71-7e5e59b4c917",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Title Only'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "slide_layout.name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "adc17d40-3579-4bb2-836c-878e54bca2ce",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Title Only\n",
      "Title and Content\n",
      "Title and Picture 1\n",
      "Title, Content, and Picture\n",
      "Title and 2 Column 1\n",
      "Tilte and Content 1 \n"
     ]
    }
   ],
   "source": [
    "for s in template.slide_layouts:\n",
    "    print(s.name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "eadceced-5f37-4948-b143-afccb9171517",
   "metadata": {},
   "outputs": [],
   "source": [
    "slide_layout = template.slide_layouts[-2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "1b6060c2-c335-4958-95d0-2dcefcef0eb1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Title and 2 Column 1'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "slide_layout.name"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74987989-87a9-422b-95ab-c2266746fa87",
   "metadata": {},
   "source": [
    "### 3. `Placeholder` 占位符\n",
    "\n",
    "`Placeholder` 是一个重要的概念，用于指示幻灯片中应该放置的内容类型（如标题、内容、图片等）。\n",
    "\n",
    "每个布局和页面都有预定义的占位符列表（`placeholders`），可以用来快速添加内容。\n",
    "\n",
    "![placeholder](../images/placeholder.png)\n",
    "\n",
    "- **属性**：\n",
    "  - `name`：占位符的名称（如标题、内容）。\n",
    "\n",
    "- **示例**：\n",
    "\n",
    "```python\n",
    "title = slide.placeholders[0]  # 获取标题占位符\n",
    "content = slide.placeholders[1]  # 获取内容占位符\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "da682d56-b515-407e-aa1a-c05c60b11522",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Title 1\n",
      "Content Placeholder 4\n",
      "Content Placeholder 4\n",
      "Footer Placeholder 4\n",
      "Slide Number Placeholder 5\n"
     ]
    }
   ],
   "source": [
    "for p in slide_layout.placeholders:\n",
    "    print(p.name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "367d1e17-acdc-4864-a357-024a73c9b803",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "pptx.shapes.placeholder.LayoutPlaceholder"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# LayoutPlaceholder 类型\n",
    "type(slide_layout.placeholders[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f19fcc5d-b3ed-4d51-afe4-b335ac556127",
   "metadata": {
    "tags": []
   },
   "source": [
    "\n",
    "### 【深入理解】Placeholder 类的继承关系（UML 类图）\n",
    "\n",
    "在 UML 类图中，我们通常使用以下符号来表示类之间的关系：\n",
    "\n",
    "- 正方形表示类名。\n",
    "- 三个部分的矩形表示类的属性和方法。\n",
    "- 箭头表示关系，如继承、关联、聚合和组合。\n",
    "\n",
    "在这个UML类图中：\n",
    "\n",
    "- **Placeholder** 是一个抽象的基类，包含了所有占位符共有的属性和方法。\n",
    "- **MasterPlaceholder** 继承自 **Placeholder**，添加了 `name` 属性，并提供了 `add_slide` 方法。\n",
    "- **LayoutPlaceholder** 继承自 **MasterPlaceholder**，添加了用于插入内容的方法，如 `insert_picture` 和 `insert_table`。\n",
    "- **PicturePlaceholder** 和 **TablePlaceholder** 都是 **LayoutPlaceholder** 的子类，它们分别添加了用于设置图片和表格的特定方法，如 `set_picture` 和 `set_table`。\n",
    "\n",
    "\n",
    "\n",
    "```\n",
    "+-------------------+\n",
    "|     Placeholder     |\n",
    "+-------------------+\n",
    "| - idx            |\n",
    "| - shape_type     |\n",
    "+-------------------+\n",
    "| + method1()      |\n",
    "| + method2()      |\n",
    "+-------------------+\n",
    "          ^\n",
    "          |\n",
    "+-------------------+\n",
    "|     MasterPlaceholder |\n",
    "+-------------------+\n",
    "| - name            |\n",
    "+-------------------+\n",
    "| + add_slide()    |\n",
    "+-------------------+\n",
    "          ^\n",
    "          |\n",
    "+-------------------+\n",
    "|     LayoutPlaceholder |\n",
    "+-------------------+\n",
    "| + insert_picture() |\n",
    "| + insert_table()   |\n",
    "+-------------------+\n",
    "          |\n",
    "          +-------------------+\n",
    "          |                   |\n",
    "          |                   |\n",
    "          v                   v\n",
    "+-------------------+     +-------------------+\n",
    "|   PicturePlaceholder |     |    TablePlaceholder |\n",
    "+-------------------+     +-------------------+\n",
    "| + set_picture()  |     | + set_table()     |\n",
    "+-------------------+     +-------------------+\n",
    "```\n",
    "\n",
    "\n",
    "请注意，这个类图是简化的，实际的Python-pptx库中的类可能包含更多的属性和方法。此外，UML类图通常包含更多的细节，如可见性（如 `+` 表示公共，`-` 表示私有）和关系类型（如泛化、实现、关联、依赖等）。在这个简化的示例中，只展示了泛化（继承）关系，并且所有的属性和方法都被假设为公共的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d184f05f-24c2-4216-92a8-a045d8357c25",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "047240b1-bd04-4b17-aa88-be81bae594e9",
   "metadata": {},
   "source": [
    "### 4. `Slide` 幻灯片\n",
    "\n",
    "`Slide` 表示 PowerPoint 演示文稿中的一张幻灯片。\n",
    "\n",
    "- **属性**：\n",
    "  - `shapes`：返回该幻灯片中的所有形状，包括文本框、图像、图表等。\n",
    "  - `slide_layout`：返回该幻灯片的布局对象，指示使用的布局类型。\n",
    "  \n",
    "- **方法**：\n",
    "  - `shapes.add_shape()`：在t 特定幻灯片上添加一个形状（例如，矩形或圆形）。\n",
    "  \n",
    "- **示例**：\n",
    "\n",
    "```python\n",
    "slide = presentation.slides.add_slide(slide_layout)  # 添加一张幻灯片\n",
    "```\n",
    "\n",
    "#### `Shape` 形状\n",
    "\n",
    "- **概述**：`Shape` 表示幻灯片中的一个形状，可以是文本框、图片、图表、SmartArt、表格等。每个 `Shape` 对象都具有位置、大小和样式属性。\n",
    "\n",
    "- **属性**：\n",
    "  - `name`: 形状名称，对应 placeholder。\n",
    "  - `left`、`top`、`width`、`height`：定义形状的位置和尺寸。\n",
    "  - `text`：如果是文本框，可以访问或修改其内容。\n",
    "  \n",
    "- **方法**：\n",
    "  - `add_textbox(left, top, width, height)`：用于在幻灯片上添加一个文本框。\n",
    "  - `add_picture(image_path, left, top, width=None, height=None)`：用于添加图片。\n",
    "  \n",
    "- **示例**：\n",
    "\n",
    "  ```python\n",
    "  textbox = slide.shapes.add_textbox(Inches(1), Inches(1), Inches(5), Inches(2))  # 添加文本框\n",
    "  ```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "e2c83967-7957-4997-980c-c21ee20b5539",
   "metadata": {},
   "outputs": [],
   "source": [
    "presentation = Presentation(\"../outputs/ChatPPT Demo.pptx\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "d2ad396d-3e15-4ccf-88ce-632d2f129e2d",
   "metadata": {},
   "outputs": [],
   "source": [
    "slide = presentation.slides[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "4b188c7c-0a35-48cd-8446-14885a67013a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'ChatPPT Demo'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "slide.shapes[0].text"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "72b575da-dc37-4d02-86bb-b42483c049d3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "slide id:0\n",
      "shape name:Title 1\n",
      "slide id:1\n",
      "shape name:Title 1\n",
      "shape name:Content Placeholder 2\n",
      "slide id:2\n",
      "shape name:Title 1\n",
      "shape name:Content Placeholder 2\n",
      "shape name:Picture Placeholder 3\n",
      "slide id:3\n",
      "shape name:Title 1\n",
      "shape name:Content Placeholder 2\n",
      "shape name:Picture Placeholder 3\n"
     ]
    }
   ],
   "source": [
    "# 打印每页形状名称\n",
    "for idx, slide in enumerate(presentation.slides):\n",
    "    print(f\"slide id:{idx}\")\n",
    "    for shape in slide.shapes:\n",
    "        print(f\"shape name:{shape.name}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e9e798d-466a-4714-9a28-7245b55ac6dd",
   "metadata": {},
   "source": [
    "### ChatPPT Demo.pptx 文件\n",
    "\n",
    "![slides](../images/slides.png)\n",
    "  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "05ff59b8-9bdc-4a4f-bc9c-96b6ccae8514",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[slide id]:0\n",
      "shape name:Title 1\n",
      "shape text:ChatPPT Demo\n",
      "\n",
      "\n",
      "[slide id]:1\n",
      "shape name:Title 1\n",
      "shape text:2024 业绩概述\n",
      "\n",
      "\n",
      "shape name:Content Placeholder 2\n",
      "shape text:\n",
      "总收入增长15%\n",
      "市场份额扩大至30%\n",
      "\n",
      "\n",
      "[slide id]:2\n",
      "shape name:Title 1\n",
      "shape text:业绩图表\n",
      "\n",
      "\n",
      "shape name:Content Placeholder 2\n",
      "shape text:\n",
      "OpenAI 利润不断增加\n",
      "\n",
      "\n",
      "shape name:Picture Placeholder 3\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'PlaceholderPicture' object has no attribute 'text'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Input \u001b[0;32mIn [17]\u001b[0m, in \u001b[0;36m<cell line: 2>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m shape \u001b[38;5;129;01min\u001b[39;00m slide\u001b[38;5;241m.\u001b[39mshapes:\n\u001b[1;32m      5\u001b[0m     \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mshape name:\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mshape\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m----> 6\u001b[0m     \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mshape text:\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mshape\u001b[38;5;241m.\u001b[39mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m      7\u001b[0m     \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n",
      "\u001b[0;31mAttributeError\u001b[0m: 'PlaceholderPicture' object has no attribute 'text'"
     ]
    }
   ],
   "source": [
    "# 打印每页形状 名称和文本，如果是非文本（如 PlaceholderPicture）将会报错\n",
    "for idx, slide in enumerate(presentation.slides):\n",
    "    print(f\"[slide id]:{idx}\")\n",
    "    for shape in slide.shapes:\n",
    "        print(f\"shape name:{shape.name}\")\n",
    "        print(f\"shape text:{shape.text}\")\n",
    "        print(\"\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4239cf1d-d7eb-4bef-92dd-c45d46362e09",
   "metadata": {},
   "source": [
    "### 【深入理解】Presentation 和 SlideMaster 类继承关系的 UML 类图\n",
    "\n",
    "在这个 UML 类图中：\n",
    "\n",
    "1. **`Presentation`** 类是顶层对象，它包含多个 `Slides` 对象。\n",
    "2. **`Slides`** 类是一个幻灯片集合，通过它可以添加或访问单独的 `Slide` 对象。\n",
    "3. **`Slide`** 类代表单个幻灯片，它包含形状（`Shapes`）和占位符（`SlidePlaceholders`），并且它通过布局（`SlideLayout`）来定义外观。\n",
    "4. **`SlideMaster`** 类包含多个 `SlideLayouts`，它定义了幻灯片的母版布局。\n",
    "5. **`SlideLayout`** 类定义了幻灯片的布局结构，其中有占位符和形状。\n",
    "6. **`Shape`** 类代表幻灯片中的形状或文本框等内容。\n",
    "\n",
    "\n",
    "```\n",
    "+------------------------+\n",
    "|      Presentation      |\n",
    "+------------------------+\n",
    "| - slides: Slides       |\n",
    "| - slide_masters: SlideMasters |\n",
    "| - slide_layouts: SlideLayouts |\n",
    "| - core_properties: CoreProperties |\n",
    "+------------------------+\n",
    "| + save(file: str)                       |\n",
    "+------------------------+\n",
    "           |\n",
    "           v\n",
    "+--------------------+\n",
    "|       Slides       |\n",
    "+--------------------+\n",
    "| - slides: Slide[]  |\n",
    "+--------------------+\n",
    "| + add_slide(layout: SlideLayout) -> Slide |\n",
    "| + get(slide_id: int) -> Slide | None      |\n",
    "+--------------------+\n",
    "           |\n",
    "           v\n",
    "+--------------------+\n",
    "|       Slide        |\n",
    "+--------------------+\n",
    "| - slide_id: int    |\n",
    "| - shapes: Shapes   |\n",
    "| - placeholders: SlidePlaceholders |\n",
    "| - slide_layout: SlideLayout       |\n",
    "+--------------------+\n",
    "| + add_shape(shape: Shape)         |\n",
    "| + add_picture(image: Picture)     |\n",
    "| + add_table(rows: int, cols: int) |\n",
    "+--------------------+\n",
    "           |\n",
    "           v\n",
    "+--------------------+\n",
    "|    SlideMaster     |\n",
    "+--------------------+\n",
    "| - slide_layouts: SlideLayouts[]  |\n",
    "+--------------------+\n",
    "| + get_by_name(name: str) -> SlideLayout |\n",
    "| + index(slide_layout: SlideLayout) -> int |\n",
    "+--------------------+\n",
    "           |\n",
    "           v\n",
    "+--------------------+\n",
    "|   SlideLayouts     |\n",
    "+--------------------+\n",
    "| - layouts: SlideLayout[] |\n",
    "+--------------------+\n",
    "| + remove(slide_layout: SlideLayout)      |\n",
    "+--------------------+\n",
    "           |\n",
    "           v\n",
    "+--------------------+\n",
    "|   SlideLayout      |\n",
    "+--------------------+\n",
    "| - placeholders: SlidePlaceholders[] |\n",
    "| - shapes: Shapes[]                  |\n",
    "| - slide_master: SlideMaster          |\n",
    "+--------------------+\n",
    "           |\n",
    "           v\n",
    "+--------------------+\n",
    "|      Shape         |\n",
    "+--------------------+\n",
    "| - name: str        |\n",
    "| - fill: FillFormat |\n",
    "| - line: LineFormat |\n",
    "+--------------------+\n",
    "| + add_textbox(left, top, width, height)  |\n",
    "| + add_picture(image_file: str)           |\n",
    "+--------------------+\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "81b5faff-3df3-45ae-b534-1d3f955943ad",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Slide ID: 256\n",
      "  Layout: <pptx.slide.SlideLayout object at 0x113688e50>\n",
      "  Shapes: 1 shapes\n",
      "  Placeholders: 1 placeholders\n",
      "  Shape Details:\n",
      "    - Shape Name: Title 1, Type: PLACEHOLDER (14)\n",
      "  Placeholder Details:\n",
      "    - Placeholder ID: 0, Type: TITLE (1)\n",
      "\n",
      "\n",
      "Slide ID: 257\n",
      "  Layout: <pptx.slide.SlideLayout object at 0x10caf1ed0>\n",
      "  Shapes: 2 shapes\n",
      "  Placeholders: 2 placeholders\n",
      "  Shape Details:\n",
      "    - Shape Name: Title 1, Type: PLACEHOLDER (14)\n",
      "    - Shape Name: Content Placeholder 2, Type: PLACEHOLDER (14)\n",
      "  Placeholder Details:\n",
      "    - Placeholder ID: 0, Type: TITLE (1)\n",
      "    - Placeholder ID: 10, Type: OBJECT (7)\n",
      "\n",
      "\n",
      "Slide ID: 258\n",
      "  Layout: <pptx.slide.SlideLayout object at 0x113658bb0>\n",
      "  Shapes: 3 shapes\n",
      "  Placeholders: 3 placeholders\n",
      "  Shape Details:\n",
      "    - Shape Name: Title 1, Type: PLACEHOLDER (14)\n",
      "    - Shape Name: Content Placeholder 2, Type: PLACEHOLDER (14)\n",
      "    - Shape Name: Picture Placeholder 3, Type: PLACEHOLDER (14)\n",
      "  Placeholder Details:\n",
      "    - Placeholder ID: 0, Type: TITLE (1)\n",
      "    - Placeholder ID: 10, Type: PICTURE (18)\n",
      "    - Placeholder ID: 35, Type: OBJECT (7)\n",
      "\n",
      "\n",
      "Slide ID: 259\n",
      "  Layout: <pptx.slide.SlideLayout object at 0x113658bb0>\n",
      "  Shapes: 3 shapes\n",
      "  Placeholders: 3 placeholders\n",
      "  Shape Details:\n",
      "    - Shape Name: Title 1, Type: PLACEHOLDER (14)\n",
      "    - Shape Name: Content Placeholder 2, Type: PLACEHOLDER (14)\n",
      "    - Shape Name: Picture Placeholder 3, Type: PLACEHOLDER (14)\n",
      "  Placeholder Details:\n",
      "    - Placeholder ID: 0, Type: TITLE (1)\n",
      "    - Placeholder ID: 10, Type: PICTURE (18)\n",
      "    - Placeholder ID: 35, Type: OBJECT (7)\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 完整打印 Slides 每一页的所有属性\n",
    "for s in presentation.slides:\n",
    "    print(f\"Slide ID: {s.slide_id}\")\n",
    "    print(f\"  Layout: {s.slide_layout}\")\n",
    "    print(f\"  Shapes: {len(s.shapes)} shapes\")\n",
    "    print(f\"  Placeholders: {len(s.placeholders)} placeholders\")\n",
    "\n",
    "    print(\"  Shape Details:\")\n",
    "    for shape in s.shapes:\n",
    "        print(f\"    - Shape Name: {shape.name}, Type: {shape.shape_type}\")\n",
    "\n",
    "    print(\"  Placeholder Details:\")\n",
    "    for placeholder in s.placeholders:\n",
    "        print(f\"    - Placeholder ID: {placeholder.placeholder_format.idx}, Type: {placeholder.placeholder_format.type}\")\n",
    "\n",
    "    print(\"\\n\")  # Adding a new line between slides for better readability"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c94a232-8e63-40f5-9516-fcfb2a345491",
   "metadata": {},
   "source": [
    "#### 输出说明：\n",
    "1. **Slide ID**: 每张幻灯片的唯一标识符。\n",
    "2. **Layout**: 使用的幻灯片布局对象。\n",
    "3. **Shapes**: 输出该幻灯片中的形状数量，并列出每个形状的详细信息（名称和类型）。\n",
    "4. **Placeholders**: 输出该幻灯片中的占位符数量，并列出每个占位符的 `ID` 和类型。\n",
    "\n",
    "---\n",
    "\n",
    "### 新增一页内容"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "0b79cfe5-1150-4b25-b6d2-3396cfa8ff90",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用 Slide_ID 获取指定页面\n",
    "last_slide_layout = presentation.slides.get(slide_id=259).slide_layout\n",
    "\n",
    "# 新增一页幻灯片\n",
    "new_slide = presentation.slides.add_slide(last_slide_layout)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "37a278b2-401c-4df8-9f36-1ea63b765ec0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 总页数变成了 5\n",
    "len(presentation.slides)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "e098963e-009c-42ae-872b-276d101ebbc4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 修改新增页标题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "99e7b2e2-a430-4b90-9f36-0af77226bf8e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Title 1'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "new_slide.shapes[0].name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "1e61a4cb-28d7-4815-bad9-2f551fdc22b0",
   "metadata": {},
   "outputs": [],
   "source": [
    "new_slide.shapes[0].text = \"测试新增页面标题\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "d1087ec4-f0fa-4d45-89cd-8ce5fb0fa31b",
   "metadata": {},
   "outputs": [],
   "source": [
    "presentation.save(\"ChatPPT_update.pptx\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c7ac64ac-ecdd-42dd-98b0-ac60f8d65d40",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "a808713e-c8eb-48c9-8b59-4fbfc6f94de3",
   "metadata": {},
   "source": [
    "## 添加页面内容的方法\n",
    "\n",
    "### 文本`TextFrame`\n",
    "\n",
    "- **概述**：`TextFrame` 表示一个文本框，包含文本和相关的格式设置。每个 `TextFrame` 可以包含多段文本。\n",
    "- **属性**：\n",
    "  - `text`：获取或设置文本框的文本内容。\n",
    "  - `paragraphs`：返回文本框中的所有段落，允许对每段进行单独格式化。\n",
    "- **示例**：\n",
    "\n",
    "```python\n",
    "text_frame = textbox.text_frame  # 获取文本框的文本框架\n",
    "text_frame.text = \"这是一段文本\"  # 设置文本内容\n",
    "```\n",
    "\n",
    "#### **文本框**\n",
    "\n",
    "在幻灯片上添加一个文本框：`add_textbox(left, top, width, height)`\n",
    "\n",
    "```python\n",
    "left = Inches(1)  # 位置\n",
    "top = Inches(1)\n",
    "width = Inches(5)\n",
    "height = Inches(2)\n",
    "textbox = slide.shapes.add_textbox(left, top, width, height)\n",
    "text_frame = textbox.text_frame  # 获取文本框内容\n",
    "text_frame.text = \"这是一段文本\"\n",
    "```\n",
    "\n",
    "#### **段落 `Paragraph`**\n",
    "\n",
    "- **概述**：`Paragraph` 表示 `TextFrame` 中的单个段落。\n",
    "- **属性**：\n",
    "  - `text`：获取或设置段落的文本内容。\n",
    "  - `font`：获取段落的字体设置，可以进行字体样式、大小和颜色的调整。\n",
    "- **示例**：\n",
    "\n",
    "```python\n",
    "paragraph = text_frame.add_paragraph()  # 添加新段落\n",
    "paragraph.text = \"这是新的段落内容。\"  # 设置段落文本\n",
    "```\n",
    "\n",
    "#### **字体 `Font`**\n",
    "\n",
    "- **概述**：`Font` 表示字体样式，允许用户设置文本的字体样式、大小、颜色等。\n",
    "- **属性**：\n",
    "  - `name`：设置字体名称。\n",
    "  - `size`：设置字体大小（使用 `Pt` 单位）。\n",
    "  - `bold`、`italic`、`underline`：设置字体的粗体、斜体和下划线样式。\n",
    "- **示例**：\n",
    "\n",
    "```python\n",
    "from pptx.util import Pt, RGBColor\n",
    "\n",
    "run = paragraph.add_run()  # 添加文本运行\n",
    "run.text = \"这是加粗的文本。\"\n",
    "run.font.bold = True  # 设置为粗体\n",
    "run.font.size = Pt(16)  # 设置字体大小\n",
    "run.font.color.rgb = RGBColor(255, 0, 0)  # 设置字体颜色为红色\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4826e67-65f3-485b-99cd-0a60c4efb246",
   "metadata": {},
   "source": [
    "### 新增文本（整合以上方法）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "8fad57e5-d2d4-4780-b925-9b49d57ebde6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Slide ID: 261\n",
      "  Layout: <pptx.slide.SlideLayout object at 0x1138f9ba0>\n",
      "  Shapes: 2 shapes\n",
      "  Placeholders: 2 placeholders\n",
      "  Shape Details:\n",
      "    - Shape Name: Title 1, Type: PLACEHOLDER (14)\n",
      "    - Shape Name: Content Placeholder 2, Type: PLACEHOLDER (14)\n",
      "  Placeholder Details:\n",
      "    - Placeholder ID: 0, Type: TITLE (1)\n",
      "    - Placeholder ID: 14, Type: OBJECT (7)\n"
     ]
    }
   ],
   "source": [
    "from pptx.util import Inches, Pt\n",
    "from pptx.dml.color import RGBColor\n",
    "\n",
    "\n",
    "# 添加文本内容幻灯片\n",
    "slide_layout = presentation.slide_layouts[-1]\n",
    "slide = presentation.slides.add_slide(slide_layout)\n",
    "\n",
    "\n",
    "# 打印新增页属性\n",
    "print(f\"Slide ID: {slide.slide_id}\")\n",
    "print(f\"  Layout: {slide.slide_layout}\")\n",
    "print(f\"  Shapes: {len(slide.shapes)} shapes\")\n",
    "print(f\"  Placeholders: {len(slide.placeholders)} placeholders\")\n",
    "\n",
    "print(\"  Shape Details:\")\n",
    "for shape in slide.shapes:\n",
    "    print(f\"    - Shape Name: {shape.name}, Type: {shape.shape_type}\")\n",
    "\n",
    "print(\"  Placeholder Details:\")\n",
    "for placeholder in slide.placeholders:\n",
    "    print(f\"    - Placeholder ID: {placeholder.placeholder_format.idx}, Type: {placeholder.placeholder_format.type}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "e2435a50-3ca9-445c-9949-80777b97a023",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 填充原有布局中的占位符（标题和文本）\n",
    "title = slide.shapes.title\n",
    "title.text = \"python-pptx 新增文本内容示例\"\n",
    "content = slide.placeholders[14]\n",
    "content.text = \"填充原有的文本占位符\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "1570ed11-df6d-4ac5-930b-a36c55c218aa",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 新增文本框\n",
    "left = Inches(6)\n",
    "top = Inches(5)\n",
    "width = Inches(5)\n",
    "height = Inches(1)\n",
    "textbox = slide.shapes.add_textbox(left, top, width, height)\n",
    "text_frame = textbox.text_frame\n",
    "text_frame.text = \"额外的文本框内容\"\n",
    "\n",
    "# 格式化文本\n",
    "paragraph = text_frame.add_paragraph()  # 添加新段落\n",
    "paragraph.text = \"这是一个新的段落。\"  # 设置段落文本\n",
    "\n",
    "# 设置字体\n",
    "run = paragraph.add_run()  # 添加文本运行\n",
    "run.text = \" 这部分是加粗的文本。\"  # 设置文本内容\n",
    "run.font.bold = True  # 设置为粗体\n",
    "run.font.size = Pt(16)  # 设置字体大小\n",
    "run.font.color.rgb = RGBColor(255, 0, 0)  # 设置字体颜色为红色\n",
    "\n",
    "# 保存 PPTX 文件\n",
    "presentation.save(\"ChatPPT_append_text.pptx\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0502d662-dcb4-40c1-b396-44ff5c283092",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "833f7cbf-7608-45f2-9ff1-3d8b836abf95",
   "metadata": {},
   "source": [
    "### 添加其他格式内容\n",
    "\n",
    "- **图片**：\n",
    "  - `add_picture(image_path, left, top, width=None, height=None)`：在幻灯片上添加图片。\n",
    "    ```python\n",
    "    slide.shapes.add_picture(\"image.png\", left, top, width, height)\n",
    "    ```\n",
    "\n",
    "- **表格**：\n",
    "  - `add_table(rows, cols, left, top, width, height)`：添加表格。\n",
    "    ```python\n",
    "    table = slide.shapes.add_table(rows, cols, left, top, width, height).table\n",
    "    ```\n",
    "\n",
    "- **图表**：\n",
    "  - `add_chart(chart_type, x, y, cx, cy, data)`：添加图表，`data` 是一个用于生成图表的数据源。\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5909d109-f5be-4360-85f6-bbf44b82c7f0",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "b7f4600a-e95b-46db-a7b1-6bb610fa1212",
   "metadata": {},
   "source": [
    "#### Homework: 使用 `python-pptx`  自动生成 PowerPoint 文件，内容包括文本、图片、表格和图表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eae0ea7f-9074-4110-984b-73ead7286003",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "34dd29c0-2813-405f-a206-22deb0b9d86e",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
